<!DOCTYPE html>
<html>
  <head>
    <title>Grid coordinates - Leaflet</title>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
    <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>

    <style>
      html,
      body {
        height: 100%;
        margin: 0;
      }
      #map {
        width: 600px;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>

    <style>
      #info {
        position: absolute;
        top: 0;
        right: 0;
        width: 20em;
        height: 7.5em;
        background: rgba(255, 255, 255, 0.5);
        z-index: 500;
        font: 12px Sans;
      }

      .crsMarker {
        border-top: 2px green solid;
        border-left: 2px green solid;
      }
    </style>

    <div id="info"></div>

    <script type="text/javascript">
      var trd = [63.41, 10.41]

      var map = L.map('map', {
        center: [40, 0],
        zoom: 1
      })

      var positron = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/attribution">CARTO</a>'
      }).addTo(map)

      var marker = L.marker(trd).addTo(map)

      // 获取 markerPane 窗格
      var pane = map.getPane('markerPane')

      // 创建一个像素原点 (pixel origin)
      // 当地图移动时，像素原点也会移动（窗格会相对于地图容器重新定位，在浏览器调试可知）
      // 当地图缩放时，像素原点会固定在屏幕的同一位置（窗格不会重新定位，但其中的图层可能会重新绘制）
      var paneCorner = document.createElement('div')
      paneCorner.style.width = '12px'
      paneCorner.style.height = '12px'
      paneCorner.style.borderTop = '2px red solid'
      paneCorner.style.borderLeft = '2px red solid'
      // 将元素追加到窗格中
      pane.appendChild(paneCorner)

      // 标记的矩形边框
      marker._icon.style.border = '1px solid green'

      // L.Map.project 方法将具有经纬度的地理点 (LatLng) 转换为像素坐标点 (Point)
      // L.Map.unproject 方法 Point -> LatLng
      // 相似的方法还有 L.Map.latLngToLayerPoint、L.Map.layerPointToLatLng

      // 创建一个 CRS 原点 (CRS origin)
      var crsMarker = L.marker(map.unproject([0, 0]), {
        icon: L.divIcon({
          className: 'crsMarker',
          iconAnchor: [0, 0]
        })
      }).addTo(map)

      // 在地图上绘制折线
      var markerOffsetLine = L.polyline(
        [
          [0, 0], // 表示一个 LatLng 地理点
          [0, 0]
        ],
        { color: 'skyblue' }
      ).addTo(map)
      var iconOffsetLine = L.polyline(
        [
          [0, 0],
          [0, 0]
        ],
        { color: 'blue' }
      ).addTo(map)

      function info() {
        // 红点：像素原点、窗格的左上角，绿点：CRS 原点
        // 缩放时像素原点的绝对像素坐标会更新，而平移时不会更新

        // 像素原点是相对于绿点的偏移坐标 (Point)
        var pixelOrigin = map.getPixelOrigin()
        // 标记底部中点相对于绿点的偏移坐标 (Point)
        var markerPixelCoords = map.project(trd, map.getZoom())
        // 标记底部中点相对于标记边框的左上角的偏移坐标 (Point)
        var markerAnchor = marker.options.icon.options.iconAnchor
        // 标记底部中点相对于红点的偏移坐标 (Point)
        var markerOffset = marker._icon._leaflet_pos

        document.getElementById('info').innerHTML =
          '<div style="color: green">CRS origin: 0,0</div>' +
          '<div style="color: red">px origin: &Delta;' + pixelOrigin.x + ',' + pixelOrigin.y + '</div>' +
          '<div style="color: blue">marker px coords:' + markerPixelCoords.x.toFixed(2) + ',' + markerPixelCoords.y.toFixed(2) + '</div>' +
          '<div style="color: blue">marker anchor: &Delta;' + markerAnchor[0] + ',' + markerAnchor[1] + '</div>' +
          '<div style="color: skyblue">marker pane offset: &Delta;' + markerOffset.x + ',' + markerOffset.y + '</div>'

        markerOffsetLine.setLatLngs([
          map.unproject(pixelOrigin),
          // 与 map.unproject(markerPixelCoords) 相同
          map.unproject(pixelOrigin.add(markerOffset))
        ])
        iconOffsetLine.setLatLngs([
          map.unproject(pixelOrigin.add(markerOffset)),
          map.unproject(pixelOrigin.add(markerOffset).subtract(markerAnchor))
        ])
      }

      map.on('load move moveend zoomend viewreset', info)

      info()
    </script>
  </body>
</html>
